// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.

#include <vector>

#include <gtest/gtest.h>

#include "fboss/platform/weutil/Crc16CcittAug.h"

using namespace facebook::fboss::platform;

TEST(Crc16CcittTest, Basic) {
  // Buffers from the test cases specified in the V5 EEPROM spec
  // https://docs.google.com/document/d/1KX6q2mHSjFU2-eDt5HGidWSRXm5vFfAaZvdOG890eXY

  // Buffer Containing 256 byte string of 'A'
  std::vector<uint8_t> buffer1(256);
  std::fill(buffer1.begin(), buffer1.end(), 'A');

  // Buffer Containing 1 byte of 'A'
  std::vector<uint8_t> buffer2(1);
  buffer2[0] = 'A';

  // Buffer Containing '123456789'
  std::vector<uint8_t> buffer3(9);
  for (int i = 0; i < 9; i++) {
    buffer3[i] = ('1' + i);
  }

  // Buffer verified with https://crccalc.com/ (as hex input): CRC-16/AUG-CCITT.
  // Captured hexdump from a montblanc eeprom as an example.
  std::vector<uint8_t> buffer4 = {
      0xfb, 0xfb, 0xff, 0x04, 0x09, 0x01, 0x49, 0x4d, 0x49, 0x4e, 0x41, 0x50,
      0x4b, 0x43, 0x02, 0x33, 0x03, 0x00, 0x20, 0x08, 0x20, 0x20, 0x20, 0x20,
      0x20, 0x20, 0x04, 0x20, 0x31, 0x0c, 0x32, 0x33, 0x30, 0x30, 0x31, 0x30,
      0x35, 0x36, 0x31, 0x30, 0x05, 0x20, 0x31, 0x0c, 0x31, 0x33, 0x30, 0x30,
      0x31, 0x30, 0x32, 0x32, 0x31, 0x30, 0x06, 0x20, 0x52, 0x0c, 0x32, 0x33,
      0x34, 0x31, 0x30, 0x47, 0x30, 0x30, 0x30, 0x32, 0x07, 0x31, 0x41, 0x0d,
      0x32, 0x30, 0x33, 0x31, 0x33, 0x32, 0x38, 0x31, 0x30, 0x30, 0x36, 0x30,
      0x01, 0x08, 0x09, 0x01, 0x00, 0x01, 0x01, 0x0a, 0x0b, 0x01, 0x2d, 0x01,
      0x03, 0x0c, 0x4c, 0x43, 0x0d, 0x53, 0x32, 0x08, 0x32, 0x30, 0x30, 0x33,
      0x31, 0x36, 0x0e, 0x30, 0x57, 0x03, 0x53, 0x55, 0x03, 0x0f, 0x54, 0x43,
      0x10, 0x48, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x06,
      0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x02, 0x13, 0x00, 0x4d, 0x03,
      0x42, 0x43, 0x02, 0xfa,
  };

  // Expected CRC Calculations for the above buffers for init value of 0x1D0F
  std::vector<std::tuple<uint8_t*, size_t, uint16_t>> expectedCrcs = {
      {buffer1.data(), buffer1.size(), 0XE938},
      {buffer2.data(), buffer2.size(), 0x9479},
      {buffer3.data(), buffer3.size(), 0xE5CC},
      {buffer4.data(), buffer4.size(), 0xC11B},
      {nullptr, 0, 0x1D0F},
  };

  for (auto& [buffer, len, expectedCrc] : expectedCrcs) {
    EXPECT_EQ(helpers::crc_ccitt_aug(buffer, len), expectedCrc);
  }
}
